package com.lyang.mall.biz.order.service.impl;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.lyang.mall.api.order.constant.OrderConstant;
import com.lyang.mall.api.order.entity.Stock;
import com.lyang.mall.api.order.entity.StockOrder;
import com.lyang.mall.api.order.enums.OrderResult;
import com.lyang.mall.api.order.service.OrderService;
import com.lyang.mall.biz.order.config.RabbitMQConfig;
import com.lyang.mall.biz.order.mapper.StockMapper;
import com.lyang.mall.biz.order.mapper.StockOrderMapper;
import com.lyang.mall.biz.order.util.RedisUtil;
import com.lyang.mall.common.entity.ResultObj;
import com.rabbitmq.tools.json.JSONUtil;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service("orderService")
public class OrderServiceImpl implements OrderService {

    @Resource
    private StockMapper stockMapper;
    @Resource
    private StockOrderMapper stockOrderMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;

    public ResultObj createOrderNoRedis(Integer stockId) {
        //由于每次都要去查询库存，增加了数据库的压力，改用缓存存储库存数据和销售数据,方法见createOrderByRedis
        Stock stock = stockMapper.selectByPrimaryKey(stockId);
        //校验库存
        ResultObj result = checkStock(stock);
        if(ResultObj.succCode!=result.getCode()){
            return result;
        }

        //减库存
        result = deductStock(stock);
        if(ResultObj.succCode!=result.getCode()){
            return result;
        }

        //创建订单
        createStockOrder(stock);
        return result;
    }

    @Override
    public ResultObj createOrder(Integer stockId) {
        Stock stock = getStockByRedis(stockId);
        //校验库存
        ResultObj result = checkStock(stock);
        if(ResultObj.succCode!=result.getCode()){
            return result;
        }
        //减库存
        result = deductStockByRedis(stock);
        if(ResultObj.succCode!=result.getCode()){
            return result;
        }
        //创建订单
        //createStockOrder(stock);
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME_ORDER, RabbitMQConfig.ROUNTING_KEY_ORDER,
                SerializationUtils.serialize(stock));
        return result;
    }

    @Override
    public void createStockOrder(Stock stock) {
        StockOrder order = new StockOrder();
        order.setName(stock.getName());
        order.setSid(stock.getId());
        order.setCreateTime(new Date());
        int i = stockOrderMapper.insert(order);
        if(i<=0){
            throw new RuntimeException("创建订单失败!");
        }
    }

    private ResultObj deductStockByRedis(Stock stock) {
        //这里还是使用数据库的乐观锁来控制，防止超卖，能不能利用redis控制呢？
        int i = stockMapper.decreaseStockOptimisticInc(stock.getId());
        if(i<=0){
            return new ResultObj(OrderResult.UPDATE_STOCK_FAIL.getCode(),OrderResult.UPDATE_STOCK_FAIL.getMsg());
        }
        //更新redis缓存数据
        RedisUtil.hincrBy(OrderConstant.REDIS_KEY_STOCK + stock.getId(), "sale", 1);
        return ResultObj.getSuccess();
    }

    private Stock getStockByRedis(Integer stockId) {
        Map<String,String> cacheDatas = RedisUtil.hgetall(OrderConstant.REDIS_KEY_STOCK+stockId);
        if(cacheDatas==null || cacheDatas.isEmpty()){
            throw new RuntimeException("缓存数据为空");
        }
        //库存总数量
        Integer count = Integer.parseInt(cacheDatas.get("count"));
        //已销售数量
        Integer sale = Integer.parseInt(cacheDatas.get("sale"));
        //名称
        String name = cacheDatas.get("name");
        //版本号
        Integer version = Integer.parseInt(cacheDatas.get("version"));
        Stock stock = new Stock();
        stock.setId(stockId);
        stock.setCount(count);
        stock.setSale(sale);
        stock.setName(name);
        stock.setVersion(version);
        return stock;
    }


    /**
     *  扣库存
     * @param stock
     * @return
     */
    private ResultObj deductStock(Stock stock) {
        //这种情况会出现超卖现象
        //stock.setSale(stock.getSale()+1);
        //int i = stockMapper.updateByPrimaryKeySelective(stock);
        //优化一：使用乐观锁(版本号)方式防止超卖
        int i = stockMapper.decreaseStockOptimistic(stock);
        if(i<=0){
            return new ResultObj(OrderResult.UPDATE_STOCK_FAIL.getCode(),OrderResult.UPDATE_STOCK_FAIL.getMsg());
        }
        return ResultObj.getSuccess();
    }

    /**
     *  校验库存是否充足
     * @param stock
     * @return
     */
    private ResultObj checkStock(Stock stock) {
        ResultObj result = ResultObj.getSuccess();
        if(stock==null){
            return  new ResultObj(OrderResult.STOCK_EMPTY.getCode(),OrderResult.STOCK_EMPTY.getMsg());
        }
        if(stock.getSale()>=stock.getCount()){
            return  new ResultObj(OrderResult.STOCK_EMPTY.getCode(),OrderResult.STOCK_EMPTY.getMsg());
        }
        return result;
    }
}
